
package todolist.logic.parser;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import todolist.util.Utils;

/**
 * Parser containing matching scheme.
 * @author Ivan
 */
public class GenericParser {

	/**
	 * Finds first match of a Phrase found at the beginning of Input, among an array of Phrases.
	 * There is a match if the first word (or more) of Input, is part of a Phrase, case insensitive.
	 * Returns the remaining input next word on, or null if no match.
	 * Empty String means there is a match without remaining Input next word on.
	 */
	public String findMatch(String[] parrPhrases, String pstrInput) {
		// no-match conditions
		if (pstrInput == null)
			return null;
		pstrInput = pstrInput.trim();
		if (pstrInput.length() == 0)
			return null;
		if (parrPhrases == null || parrPhrases.length == 0)
			return null;
		for (String strPhrase : parrPhrases) { // match each phrase
			String strRemaining = findMatchRecursive(strPhrase, "", pstrInput); // get shortest remaining String possible
			if (strRemaining != null)
				return strRemaining;
		}
		return null; // all phrases do not match
	}

	// private methods
	
	/**
	 * Finds match of a Phrase existing at the beginning of Input.
	 * There is a match if the beginning of Input is part (substring) of a Phrase, case insensitive.
	 * Returns unparsed String from the next word on, or null if no match found.
	 * null/empty Phrase should never have matches. Single word-characters in input should never have matches too.
	 * @throws IllegalArgumentException
	 */
	private String findMatchRecursive(String pstrPhrase, String pstrInputFront, String pstrInputBack) throws IllegalArgumentException {
		// parameter validation
		if (pstrInputFront == null || pstrInputBack == null)
			throw new IllegalArgumentException("GenericParser.findMatchRecursive(): Inputs/Phrase cannot be null.");
		// base cases
		String strCurrWord = pstrInputBack.split("\\s+")[0].trim();
		String strNewInputFront = pstrInputFront + (pstrInputFront.equals("") ? "" : " ") + strCurrWord;
		String strNewInputBack = Utils.discardNWordsFromString(pstrInputBack, 1);
		if (pstrPhrase == null || pstrPhrase.length() == 0 ||
			strNewInputFront.length() == 0)
			return null; // definitely no match on ""
		if (strCurrWord.length() == 1 && strCurrWord.matches("\\w"))
			return null; // definitely no match on single word-character
		// recursively find match
		Pattern objPattern = Pattern.compile(Pattern.quote(strNewInputFront) + "\\s*(.*)", Pattern.CASE_INSENSITIVE);
		Matcher objMatcher = objPattern.matcher(pstrPhrase);
		if (!objMatcher.matches())
			return null; // no match
		// match at this point, try for longer matches
		String strUnparsed = findMatchRecursive(pstrPhrase, strNewInputFront, strNewInputBack);
		if (strUnparsed == null)
			return strNewInputBack; // this is the longest match
		return strUnparsed; // return longer match
	}
	
}
